#include <ArduinoJson.h>
#include <PubSubClient.h>
#include <WiFiEsp.h>
// #ifndef HAVE_HWSERIAL1
// #include "Software//Serial.h"
// Software//Serial //Serial1(10, 11); // RX, TX use for contact with esp8266
// #endif
#include <DHT.h>
#define DECODE_NEC
//#define DECODE_DENON
#include <IRremote.h>
#define MESSAGE_LENGTH 128

#define DHTTYPE DHT11 // DHT 11
#define DHTPIN 4      // DHT 11;

#define button_0 2
#define button_1 3
#define buzzer_0 5
#define led_0 7
#define led_1 8
#define lightSensor_0 A1
#define pot_0 A0
#define relay_0 12

#define RECV_PIN 6
// Irremote
IRrecv irrecv(RECV_PIN);
decode_results results;

// Sensors config
DHT dht(DHTPIN, DHTTYPE);

// Function prototypes
void callback(char *topic, byte *payload, unsigned int length);
void initWiFi();
void connectToMqttServer();
void initServer();
void pubMessage(char *topic, char *message);
void actfromjson(char *jsonstr);
void initpin();
void sign();

// Set your MAC address and IP address here
byte mac[] = {0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED};
IPAddress ip(192, 168, 0, 3);

// Make sure to leave out the http and slashes!
const char *server = "dashiandjie.top";
const char *ssid = "360WiFi-311";
const char *psk = "311311311";
const char *topic = "lot";
const char *topic_from_server = "server";
long lastMsg = 0;
byte reSub = 0;

// Ethernet and MQTT related objects
WiFiEspClient client;
PubSubClient mqttClient(client);

WiFiEspServer WiFiServer(66);

//init the statu of wifi
int status = WL_IDLE_STATUS;
boolean isRenewed = false;

//recall from mtqq
char message[MESSAGE_LENGTH] = "";

void sign()
{
    digitalWrite(led_0, LOW);
    delay(500);
    digitalWrite(led_0, HIGH);
    delay(500);
    digitalWrite(led_0, LOW);
    delay(500);
    digitalWrite(led_0, HIGH);
}

void initPin()
{
    pinMode(button_0, INPUT);
    pinMode(button_1, INPUT);
    pinMode(buzzer_0, OUTPUT);
    pinMode(led_0, OUTPUT);
    pinMode(led_1, OUTPUT);
    pinMode(lightSensor_0, INPUT);
    pinMode(pot_0, INPUT);
    pinMode(relay_0, OUTPUT);

    //init IrRemote
    irrecv.enableIRIn(); // Start the receiver

    //DHT
    dht.begin();
}

void actFromJson(char *jsonstr)
{
    sign();
    StaticJsonDocument<MESSAGE_LENGTH> doc;
    // Deserialize the JSON document
    DeserializationError error = deserializeJson(doc, jsonstr);

    // Test if parsing succeeds.
    if (error)
    {
        //Serial.println(error.f_str());
        return;
    }
    byte type = doc["type"];
    //Serial.print("type :");
    //Serial.println(type);

    //#define button_0  2
    //#define button_1  3
    //#define buzzer_0  5
    //#define led_0  7
    //#define led_1  8
    //#define lightSensor_0  A1
    //#define pot_0 A0
    //#define relay_0 12
    //
    //#define RECV_PIN 6
    if (type == 0)
    {
        //Serial.println("case0");
        char *sensor = doc["name"];
        doc.clear();
        if (strcmp(sensor, "temp") == 0)
        { //温度
            doc["name"] = "temp";
            doc["temp"] = (float)dht.readTemperature();
            float data = doc["temp"];
            //Serial.println(data);
        }
        else if (strcmp(sensor, "humi") == 0)
        { //湿度
            doc["name"] = "humi";
            doc["humi"] = (float)dht.readHumidity();
        }
        else if (strcmp(sensor, "pote") == 0)
        { //电位器
            doc["name"] = "pote";
            doc["pote"] = (float)digitalRead(pot_0);
        }
        else if (strcmp(sensor, "phto") == 0)
        { //光敏
            doc["name"] = "phto";
            doc["phto"] = (float)digitalRead(pot_0);
        }
        else if (strcmp(sensor, "infr") == 0)
        { //红外
            // if (irrecv.decode(&results)) {
            //   ////Serial.println(results.value, HEX);
            //   irrecv.resume(); // Receive the next value
            // }
            // doc["name"] = "infr";
            // doc["infr"] = results.value;
        }
        // serializejosn and publish
        serializeJson(doc, message, MESSAGE_LENGTH);
        //Serial.print("serialized message: ");
        //Serial.println(message);
        pubMessage(topic, message);
    }
    else if (type == 1)
    {
        //Serial.println("case1");
        char *controller = doc["name"];
        byte value = doc["val"];
        if (strcmp(controller, "led1") == 0)
        { //led1
            digitalWrite(led_0, value);
        }
        else if (strcmp(controller, "led2") == 0)
        { //led2
            digitalWrite(led_1, value);
        }
        else if (strcmp(controller, "swit") == 0)
        { //开关
            digitalWrite(relay_0, value);
        }
    }
    else if (type == 2)
    {
        //Serial.println("case2");
        char *control = doc["name"];
        if (strcmp(control, "beep") == 0)
        { //蜂鸣器
            digitalWrite(buzzer_0, HIGH);
            tone(buzzer_0, 392, 1000);
            noTone(buzzer_0);
        }
    }

    doc.clear();
    doc["status"] = 200;
    serializeJson(doc, message, MESSAGE_LENGTH);
    pubMessage(topic, message);
}

void initWiFi()
{
    Serial.begin(9600);
    WiFi.init(&Serial);
    status = WiFi.status();
    delay(5000);
    while (status != WL_CONNECTED)
    {
        //Serial.println("connect to network...");
        //Serial.print("SSID: ");
        //Serial.println(ssid);

        status = WiFi.begin(ssid, psk);
        // wifi takes some time to boot!
        delay(5000);
        //renew the status of wifi
        status = WiFi.status();
        if (status != WL_CONNECTED)
        {
            //Serial.println("wifi lost,trying again!");
        }
    }
}

void initServer()
{
    // Set the MQTT server to the server stated above
    mqttClient.setServer(server, 1883);
    // Set the message buffer
    mqttClient.setBufferSize(1024);
    // Set the heartbeats circle
    mqttClient = mqttClient.setKeepAlive(24);

    mqttClient = mqttClient.setSocketTimeout(24);
}

void connectToMqttServer()
{
    //init the mqtt server options
    initServer();

    // Attempt to connect to the server with the ID "myClientID"
    while (!mqttClient.connect("ard"))
    {
        //Serial.println("Connection lost, trying again");
        delay(1000);
    }
    //Serial.println("connectted");

    // Establish the subscribe event
    //mqttClient.setCallback(callback);

    //mqttClient.subscribe(topic_from_server, 1);
}

void pubMessage(char *topic, char *message)
{
    while (!mqttClient.connected())
    {
        //Serial.println(mqttClient.state());
        mqttClient.connect("ard");
        //mqttClient.subscribe(topic_from_server, 1);
    }
    if (mqttClient.publish(topic, message))
    {
        ////Serial.println("Publish message success");
    }
    else
    {
        //Serial.println("fixing wifi...");
        if (WiFi.status() != WL_CONNECTED)
        {
            initWiFi();
        }
    }
}

void setup()
{
    // put your setup code here, to run once:
    // Useful for debugging purposes
    //Serial.begin(9600);

    initPin();

    // Start the wifi connection
    initWiFi();

    delay(1000);
    digitalWrite(led_1, HIGH);
    delay(1000);
    digitalWrite(led_1, LOW);

    connectToMqttServer();

    WiFiServer.begin();
    IPAddress myAddress = WiFi.localIP();

    digitalWrite(led_0, HIGH);
    digitalWrite(led_1, HIGH);
    delay(1000);
    digitalWrite(led_0, LOW);
}

void loop()
{
    digitalWrite(led_0, HIGH);
    delay(5);
    digitalWrite(led_0, LOW);
    mqttClient.loop();
    // long now = millis();
    // if (now - lastMsg > 2000)
    // {
    //     lastMsg = now;
    //     // Attempt to reconnect
    //     pubMessage("alive", "OK");
    // }

    WiFiEspClient thisClient = WiFiServer.available();
    if (thisClient)
    {
        int len = 0;
        boolean currentLineIsBlank = true;
        while (thisClient.connected())
        {
            if (thisClient.available())
            {
                char c = thisClient.read();
                message[len] = c;
                if (c == '\n' && currentLineIsBlank)
                {
                    message[len] = '\0';
                    break;
                }
                if (c == '\n')
                {
                    // you're starting a new line
                    currentLineIsBlank = true;
                }
                else if (c != '\r')
                {
                    // you've gotten a character on the current line
                    currentLineIsBlank = false;
                }
                len++;
            }

        }
        thisClient.print("OK");
        delay(10);
        thisClient.stop();
        pubMessage("alive", message);
        actFromJson(message);
    }
}

//message recived method
void callback(char *topic, byte *payload, unsigned int length)
{
    // Print the topic
    //Serial.print("Topic: ");
    //Serial.println(topic);

    // Print the message
    //Serial.print("Message: ");
    //   for(int i=0; i < length; i++){
    //     //Serial.print((char)payload[i]);
    //   }
    //Serial.println();
    memcpy(message, payload, length);
    // actFromJson(message);
    ////Serial.print(payload);
    // Print a newline
    ////Serial.println("");
    isRenewed = true;

    //get the result
    //  message = (char*)(payload);
    //  //Serial.println(message);
}